package core;

import java.util.ArrayList;

public class Util {

	public final static long MASK = 0xff; 
	
	public static String getString(byte[] data){
		String ret = "";
		for(int i=0; i<data.length; i++){
			ret += ((char)data[i]);
		}
		return ret;
	}

	/**
	 * This string translation removes all null bytes (bit value 0),
	 *  which cause problems when printing strings.
	 * @param data
	 * @return
	 */
	public static String getString2(byte[] data){
		String ret = "";
		for(int i=0; i<data.length; i++){
			if( data[i] != 0){
				ret += ((char)data[i]);
			}
		}
		return ret;
	}
	
	public static String getRepresentation(byte[] data){
		String ret = "";
		for(int i=0; i<data.length; i++){
			ret += data[i]+".";
		}
		return ret.substring(0,ret.length()-1);
	}
	
	public static byte[] getBytes(String str){
		byte[] ret = new byte[str.length()];
		for(int i=0; i<ret.length; i++){
			ret[i] = (byte)str.charAt(i);
		}
		return ret;
	}
	
	public static int indexOf(byte[] b, char c){
		for(int i=0; i<b.length; i++){
			if(b[i] == c){
				return i;
			}
		}
		return -1;
	}
	
	public static int lastIndexOf(byte[] b, char c){
		for(int i=b.length-1; i>= 0; i--){
			if(b[i] == c){
				return i;
			}
		}
		return -1;
	}
	
	public static byte[] combine(byte[] a, byte[] b){
		byte[] ret = new byte[a.length+b.length];
		for(int i=0; i<a.length; i++){
			ret[i]=a[i];
		}
		for(int i=0; i<b.length; i++){
			ret[i+a.length]=b[i];
		}
		return ret;
	}

	public static String flatten(String[] str){
		String ret = "";
		for(String s : str){
			ret += s+" ";
		}
		return ret.substring(0,ret.length()-1)+"";
	}
	
	/**
	 * This method compares 2 times and determines if they are farther apart then lapse.
	 * @param one first time to compare
	 * @param two second time to compare
	 * @param lapse the maximum lapse time before returning true
	 * @return returns true if '|one-two| > |lapse|' 
	 */
	public static boolean timeLapsed(long one, long two, long lapse){
		return Math.abs(one-two) > lapse;
	}
	
	public static String pad(String str, char c, int sz){
		String ret = str;
		while(ret.length() < sz){
			ret = c+ret;
		}
		return ret;
	}
	
	/**
	 * Shift bytes in the array so that they form a long.
	 * Assuming the first byte is the highest order.
	 * example if they are properly bit shifted they would align:
	 * [0][1][2]...[n-1][n]
	 * @param a Array, or multiple bytes to turn into a long
	 * @return
	 */
	public static long add(byte ...a){
		long r = 0;
		for(int i=a.length; i>0; i--){
			long l = sU(a[i-1],a.length-i);
			System.out.println(i+" "+(a.length-i)+" "+a[i-1]+" "+l);
			r += l;
		}
		return r;
	}
	public static long sU(byte b, int s){
		long mask = MASK << (s*8);
		long l = ((long)b)<<(s*8);
		return (l & mask);
	}
	public static byte[] breakB(int i){
		return breakB((long)i);
	}

	public static byte[] breakB(long l){
		ArrayList<Byte> b = new ArrayList<Byte>();
		System.out.println(l);
		while(l != 0){
			byte c = (byte) (l & MASK);
			b.add(0, c);
			l = l >>> 8;
		}
		return convertByte(b.toArray());
	}
	
	
	public static byte[] convertByte(Object[] o){
		byte[] b = new byte[o.length];
		for(int i=0;i<o.length;i++){
			b[i] = (Byte)o[i];
		}
		return b;
	}

	
	private static long x = System.nanoTime();
	
	public static void setSeed(long i){
		x=i;
	}

	public static long randomLong() {
		  x ^= (x << 21);
		  x ^= (x >>> 35);
		  x ^= (x << 4);
		  return x;
	}
	

	/**
	 * This method takes string 's' and splits it into pieces of length 'i'
	 * @param s String to split.
	 * @param i Size of pieces to break it into.
	 * @return Returns an array of Strings where String[0] corresponds
	 *  to the beginning of 's' and has a length 'i'
	 */
	public static String[] split(String s, int i){
		if(s.length()%i != 0){
			i =i+ (s.length()/i);
		}else{
			i = (s.length()/i);
		}
		String[] ret = new String[i];
		for(int j=0; j<s.length(); j+= i){
			if(j+i > s.length()){
				ret[j] = s.substring(j,s.length());
			}else{
				ret[j] = s.substring(j,j+i);
			}
		}
		return ret;
	}
	
	/**
	 * To simplify the flow of exceptions, if 'std' is true, then the exception is written to stdout.
	 * Otherwise it's written to ErrOut. 
	 * @param e Exception to print.
	 * @param std true if the exception is to go to stdOut
	 */
	public static void printException(Exception e, boolean std){
		if(std){
			e.printStackTrace(System.out);
		}else{
			e.printStackTrace();
		}
	}
	
}
